extern "C"
{
#include "../renderer/tr_local.h"
}
#include "tr_r2.h"

using namespace TDP;

refimport_t	ri;
glconfig_t	glConfig;
glstate_t	glState;

#define R2_TRY	PanicHandler ph; if(!setjmp(ph.JumpTarget())) {

#define R2_CATCH	} else { Com_Error(ERR_DROP, "TDP experienced a fatal error.  Code %i", static_cast<int>(ph.ErrorCode())); }


void		R2_ClearScene_ep( void ) {
	R2_TRY
	R2_ClearScene();
	R2_CATCH
}

void		R2_AddRefEntityToScene_ep( const refEntity_t *ent ) {
	R2_TRY
	R2_AddRefEntityToScene(ent);
	R2_CATCH
}

void		R2_AddPolyToScene_ep( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ) {
	R2_TRY
	R2_AddPolyToScene(hShader, numVerts, verts, num);
	R2_CATCH
}

void		R2_AddLightToScene_ep( const vec3_t org, float intensity, float r, float g, float b ) {
	R2_TRY
	R2_AddLightToScene(org, intensity, r, g, b);
	R2_CATCH
}

void		R2_AddAdditiveLightToScene_ep( const vec3_t org, float intensity, float r, float g, float b ) {
	R2_TRY
	R2_AddAdditiveLightToScene(org, intensity, r, g, b);
	R2_CATCH
}

void		R2_RenderScene_ep( const refdef_t *fd ) {
	R2_TRY
	R2_RenderScene(fd);
	R2_CATCH
}


void		R2_StretchRaw_ep (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
	R2_TRY
	R2_StretchRaw(x, y, w, h, cols, rows, data, client, dirty);
	R2_CATCH
}

void		R2_UploadCinematic_ep (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
	R2_TRY
	R2_UploadCinematic(w, h, cols, rows, data, client, dirty);
	R2_CATCH
}

void		R2_BeginRegistration_ep( glconfig_t *glconfig ) {
	R2_TRY
	R2_BeginRegistration(glconfig);
	R2_CATCH
}

void		R2_LoadWorldMap_ep( const char *mapname ) {
	R2_TRY
	R2_LoadWorldMap(mapname);
	R2_CATCH
}

void		R2_SetWorldVisData_ep( const byte *vis ) {
	R2_TRY
	R2_SetWorldVisData(vis);
	R2_CATCH
}

qhandle_t	R2_RegisterModel_ep( const char *meshName, const char *skelName ) {
	qhandle_t h = 0;
	R2_TRY
	h = R2_RegisterModel(meshName, skelName);
	R2_CATCH
	return h;
}

qhandle_t	R2_RegisterSkin_ep( const char *name ) {
	qhandle_t h = 0;
	R2_TRY
	h = R2_RegisterSkin(name);
	R2_CATCH
	return h;
}

void		R2_Shutdown_ep( qboolean destroyWindow ) {
	R2_TRY
	R2_Shutdown(destroyWindow);
	R2_CATCH
}

qhandle_t	R2_RegisterShader_ep( const char *name ) {
	qhandle_t h = 0;
	R2_TRY
	h = R2_RegisterShader(&ph, name);
	R2_CATCH
	return h;
}

qhandle_t	R2_RegisterShaderNoMip_ep( const char *name ) {
	qhandle_t h = 0;
	R2_TRY
	h = R2_RegisterShaderNoMip(&ph, name);
	R2_CATCH
	return h;
}

qhandle_t	R2_RegisterShaderFromImage_ep(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage) {
	qhandle_t h = 0;
	R2_TRY
	h = R2_RegisterShaderFromImage(name, lightmapIndex, image, mipRawImage);
	R2_CATCH
	return h;
}

void		R2_ShutdownShaders_ep() {
	R2_TRY
	R2_ShutdownShaders();
	R2_CATCH
}

void		R2_ShutdownModels_ep() {
	R2_TRY
	R2_ShutdownModels();
	R2_CATCH
}


void		R2_EndRegistration_ep( void ) {
	R2_TRY
	R2_EndRegistration();
	R2_CATCH
}


void		R2_SetColor_ep( const float *rgba ) {
	R2_TRY
	R2_SetColor(rgba);
	R2_CATCH
}

void		R2_StretchPic_ep ( float x, float y, float w, float h, 
					  float s1, float t1, float s2, float t2, qhandle_t hShader ) {
	R2_TRY
	R2_StretchPic(x, y, w, h, s1, t1, s2, t2, hShader);
	R2_CATCH
}


void		R2_EndFrame_ep( int *frontEndMsec, int *backEndMsec ) {
	R2_TRY
	R2_EndFrame(frontEndMsec, backEndMsec);
	R2_CATCH
}


int			R2_MarkFragments_ep( int numPoints, const vec3_t *points, const vec3_t projection,
				   int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
	int r = 0;
	R2_TRY
	r = R2_MarkFragments(numPoints, points, projection, maxPoints, pointBuffer, maxFragments, fragmentBuffer);
	R2_CATCH
	return r;
}

int			R2_LerpTag_ep( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, 
					 float frac, const char *tagName ) {
	int r = 0;
	R2_TRY
	r = R2_LerpTag(tag, handle, startFrame, endFrame, frac, tagName);
	R2_CATCH
	return r;
}

void		R2_ModelBounds_ep( qhandle_t handle, vec3_t mins, vec3_t maxs ) {
	R2_TRY
	R2_ModelBounds(handle, mins, maxs);
	R2_CATCH
}

int			R2_LightForPoint_ep( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) {
	int r = 0;
	R2_TRY
	r = R2_LightForPoint(point, ambientLight, directedLight, lightDir);
	R2_CATCH
	return r;
}

void		R2_RegisterFont_ep(const char *fontName, int pointSize, fontInfo_t *font) {
	R2_TRY
	R2_RegisterFont(fontName, pointSize, font);
	R2_CATCH
}

void		R2_RemapShader_ep(const char *oldShader, const char *newShader, const char *timeOffset) {
	R2_TRY
	R2_RemapShader(oldShader, newShader, timeOffset);
	R2_CATCH
}

qboolean	R2_GetEntityToken_ep( char *buffer, int size ) {
	qboolean r = qfalse;
	R2_TRY
	r = R2_GetEntityToken(buffer, size);
	R2_CATCH
	return r;
}

qboolean	R2_inPVS_ep( const vec3_t p1, const vec3_t p2 ) {
	qboolean r = qfalse;
	R2_TRY
	r = R2_inPVS(p1, p2);
	R2_CATCH
	return r;
}

void		R2_BeginFrame_ep( stereoFrame_t stereoFrame ) {
	R2_TRY
	R2_BeginFrame(stereoFrame);
	R2_CATCH
}


void		R2_InitTBR_ep() {
	R2_TRY
	R2_InitTBR();
	R2_CATCH
}

void		R2_WaitForLoader_ep() {
	R2_TRY
	R2_WaitForLoader();
	R2_CATCH
}

void	R2_FatalError( RDX::OperationContext *ctx )
{
	Com_Error( ERR_DROP, "RDX experienced a fatal error.  Code %i", static_cast<int>(ctx->errorCode) );
}




/*
@@@@@@@@@@@@@@@@@@@@@
GetRefAPI

@@@@@@@@@@@@@@@@@@@@@
*/
refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp )
{
	static refexport_t	re;

	ri = *rimp;

	Com_Memset( &re, 0, sizeof( re ) );

	// riot - TODO: See if this is ever called without a Shutdown()
	// call to see if glState/glConfig should be cleared

	if ( apiVersion != REF_API_VERSION ) {
		ri.Printf(PRINT_ALL, "Mismatched REF_API_VERSION: expected %i, got %i\n", 
			REF_API_VERSION, apiVersion );
		return NULL;
	}

	// the RE_ functions are Renderer Entry points

	re.Shutdown = R2_Shutdown_ep;

	re.BeginRegistration = R2_BeginRegistration_ep;
	re.RegisterModel = R2_RegisterModel_ep;
	re.RegisterSkin = R2_RegisterSkin_ep;
	re.RegisterShader = R2_RegisterShader_ep;
	re.RegisterShaderNoMip = R2_RegisterShaderNoMip_ep;
	re.LoadWorld = R2_LoadWorldMap_ep;
	re.SetWorldVisData = R2_SetWorldVisData_ep;
	re.EndRegistration = R2_EndRegistration_ep;

	re.BeginFrame = R2_BeginFrame_ep;
	re.EndFrame = R2_EndFrame_ep;

	re.MarkFragments = R2_MarkFragments_ep;
	re.LerpTag = R2_LerpTag_ep;
	re.ModelBounds = R2_ModelBounds_ep;

	re.ClearScene = R2_ClearScene_ep;
	re.AddRefEntityToScene = R2_AddRefEntityToScene_ep;
	re.AddPolyToScene = R2_AddPolyToScene_ep;
	re.LightForPoint = R2_LightForPoint_ep;
	re.AddLightToScene = R2_AddLightToScene_ep;
	re.AddAdditiveLightToScene = R2_AddAdditiveLightToScene_ep;
	re.RenderScene = R2_RenderScene_ep;

	re.SetColor = R2_SetColor_ep;
	re.DrawStretchPic = R2_StretchPic_ep;
	re.DrawStretchRaw = R2_StretchRaw_ep;
	re.UploadCinematic = R2_UploadCinematic_ep;

	re.RegisterFont = R2_RegisterFont_ep;
	re.RemapShader = R2_RemapShader_ep;
	re.GetEntityToken = R2_GetEntityToken_ep;
	re.inPVS = R2_inPVS_ep;

	re.WaitForLoader = R2_WaitForLoader_ep;

	return &re;
}
